package com.seguriapp.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;

/**
 * Servlet that handles file uploads
 * 
 * @author Tania Gonzales (taniadgv@gmail.com)
 */
public class CommonsFileUploadServlet extends HttpServlet {

  private static final long serialVersionUID = 1L;
//  private static final String TMP_DIR_PATH = "/home/redcat/webapps/uploaded";
  private static final String TMP_DIR_PATH = "C:\\test";
  private File tmpDir;
//  public static final String DESTINATION_DIR_PATH = "/home/redcat/webapps/uploaded";
  public static final String DESTINATION_DIR_PATH = "C:\\test";
  private File destinationDir;

  private static final String PERSON_ID_UPLOAD = "PersonProfileId";
  private static final String INPUT_ID = "inputId";
  public static final String TMP_PERSON_PHOTO_NAME = "TmpProfilePhoto";
  public static final String TMP_PERSON_CONTACTS_FILE = "ContactsFile";
  public static final String PERSON_PHOTO_UPLOAD_TYPE = "profilephoto";
  public static final String RESUME_UPLOAD_TYPE = "resumefile";
  public static final String CONTACTS_UPLOAD_TYPE = "contactsfile";
  public static final String UPLOAD_TYPE = "uploadType";
  public static final String GROUP_UPLOAD_TYPE = "groupPicture";
  public static final String EVENT_UPLOAD_TYPE = "eventPicture";
  public static final int FILE_SIZE = 1024;
  public static final int FILE_NAME_SIZE = 16;
  private static final String SPACE = " ";
  private static final String UNDERLINE = "_";
  private static final String SUCCESS_TRUE = "success: true";
  private static final String SUCCESS_FALSE = "{success: false}";
  private static final String SUCCESS_FALSE_SIZE = "{fileSizeError: true}";
  private static final String RESPONSE_FORMAT = "{%s, %s'%s'}";
  private static final String FILE_NAME = "fileName: ";
  private static final long PHOTO_MAX_SIZE = 4194304;

  private static final Logger LOGGER = Logger.getLogger(CommonsFileUploadServlet.class);

  /**
   * {@inheritDoc}
   * 
   * @param config
   * @throws ServletException
   */
  @Override
  public void init(ServletConfig config) throws ServletException {
    super.init(config);
    tmpDir = new File(TMP_DIR_PATH);
    if (!tmpDir.isDirectory()) {
      throw new ServletException(TMP_DIR_PATH + " is not a directory");
    }
    destinationDir = new File(DESTINATION_DIR_PATH);
    if (!destinationDir.isDirectory()) {
      throw new ServletException(DESTINATION_DIR_PATH + " is not a directory");
    }
  }

  /**
   * Handles the HTTP <code>POST</code> method.
   * 
   * @param request
   *          servlet request
   * @param response
   *          servlet response
   * @throws ServletException
   *           if a servlet-specific error occurs
   * @throws IOException
   *           if an I/O error occurs
   */
  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException {
    System.out.println("========U P L O A D ============");

    PrintWriter writer = null;
    InputStream is = null;
    FileOutputStream fos = null;
    response.setContentType("text/plain");
    try {
      writer = response.getWriter();
    } catch (IOException ex) {
      log(CommonsFileUploadServlet.class.getName() + "has thrown an exception: " + ex.getMessage());
    }

    String filename = request.getHeader("X-File-Name") == null ? request.getParameter("qqfile") : request.getHeader("X-File-Name");
    try {
      if (ServletFileUpload.isMultipartContent(request)) {
        String responseStr = uploadFileFromForm(request, response, filename);
        response.setStatus(HttpServletResponse.SC_OK);
        writer.print(responseStr);
      } else {
        is = request.getInputStream();
        fos = new FileOutputStream(new File(String.format("%s/%s", DESTINATION_DIR_PATH, filename)));
        IOUtils.copy(is, fos);
        response.setStatus(HttpServletResponse.SC_OK);
        writer.print("{" + SUCCESS_TRUE + "}");
      }
    } catch (FileNotFoundException ex) {
      response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      writer.print(SUCCESS_FALSE);
      LOGGER.error("Error encountered while parsing the request", ex);
    } catch (IOException ex) {
      response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      writer.print(SUCCESS_FALSE);
      LOGGER.error("Error encountered while parsing the request", ex);
    } catch (Exception ex) {
      response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      writer.print(SUCCESS_FALSE);
      LOGGER.error("Error encountered while parsing the request", ex);
    } finally {
      try {
        if (fos != null) {
          fos.close();
        }
        if (is != null) {
          is.close();
        }
      } catch (IOException ignored) {
      }
    }

    // writer.flush();
    writer.close();
  }

  @SuppressWarnings("rawtypes")
  private String uploadFileFromForm(HttpServletRequest request, HttpServletResponse response, String filename) throws IOException {
    String responseStr = null;
    response.setContentType("text/plain");
    DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
    /*
     * Set the size threshold, above which content will be stored on disk.
     */
    fileItemFactory.setSizeThreshold(1 * FILE_SIZE * FILE_SIZE); // 1 MB
    /*
     * Set the temporary directory to store the uploaded files of size above
     * threshold.
     */
    fileItemFactory.setRepository(tmpDir);

    ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);
    try {
      /*
       * Parse the request
       */
      List items = uploadHandler.parseRequest(request);
      Iterator itr = items.iterator();

      FileItem uploadedItem = null;
      FileItem item;
      String uploadType = request.getParameter(UPLOAD_TYPE);
      String inputId = request.getParameter(INPUT_ID);
      String idMember = request.getParameter(PERSON_ID_UPLOAD);
      String otherPath = DESTINATION_DIR_PATH;
      if (idMember != null && !idMember.isEmpty()) {
        destinationDir = new File(String.format("%s/%s", DESTINATION_DIR_PATH, idMember));
      }
      while (itr.hasNext()) {
        item = (FileItem) itr.next();
        if (!item.isFormField()) {
          uploadedItem = item;
        }
      }
      /*
       * Write file to the ultimate location.
       */
      if (uploadedItem != null) {
        if (!destinationDir.exists()) {
          destinationDir.mkdirs();
        }
        if (PHOTO_MAX_SIZE < uploadedItem.getSize()) {
          return SUCCESS_FALSE_SIZE;
        }
        String fileName = Util.randomString(FILE_NAME_SIZE);
        String fileExt = uploadedItem.getName().substring(uploadedItem.getName().lastIndexOf(".")).toLowerCase();
        if (CONTACTS_UPLOAD_TYPE.equals(uploadType)) {
          File file = new File(destinationDir, TMP_PERSON_CONTACTS_FILE + ".csv");
          uploadedItem.write(file);
          responseStr = String.format(RESPONSE_FORMAT, SUCCESS_TRUE, FILE_NAME, file.getName());
        } else if (PERSON_PHOTO_UPLOAD_TYPE.equals(uploadType)) {
          File file = new File(destinationDir, fileName.concat(fileExt));
          uploadedItem.write(file);
          responseStr = String.format(RESPONSE_FORMAT, SUCCESS_TRUE, FILE_NAME, fileName.concat(fileExt));
        } else if (GROUP_UPLOAD_TYPE.equals(uploadType)) {
          File tempFile = new File(otherPath + "/groups/" + idMember);
          if (!tempFile.exists()) {
            tempFile.mkdirs();
          }
          File file = new File(tempFile, fileName.concat(fileExt));
          uploadedItem.write(file);
          responseStr = String.format(RESPONSE_FORMAT, SUCCESS_TRUE, FILE_NAME, fileName.concat(fileExt));
        } else if (EVENT_UPLOAD_TYPE.equals(uploadType)) {
          File tempFile = new File(otherPath + "/events/" + idMember);
          if (!tempFile.exists()) {
            tempFile.mkdirs();
          }
          File file = new File(tempFile, fileName.concat(fileExt));
          uploadedItem.write(file);
          responseStr = String.format(RESPONSE_FORMAT, SUCCESS_TRUE, FILE_NAME, fileName.concat(fileExt));
        } else if (RESUME_UPLOAD_TYPE.equals(uploadType)) {
          File file = new File(destinationDir, filename.replace(SPACE, UNDERLINE));
          uploadedItem.write(file);
          responseStr = String.format("{%s, %s: '%s', %s'%s'}", SUCCESS_TRUE, INPUT_ID, inputId, FILE_NAME, fileName.concat(fileExt));
        }
      }
    } catch (FileUploadException ex) {
      LOGGER.error("Error encountered while parsing the request", ex);
    } catch (Exception ex) {
      LOGGER.error("Error encountered while uploading file", ex);
    }
    return responseStr;
  }
}
